/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef vm_NativeObject_inl_h#define vm_NativeObject_inl_h#include"vm/NativeObject.h"#include"jscntxt.h"#include"builtin/TypedObject.h"#include"proxy/Proxy.h"#include"vm/ProxyObject.h"#include"vm/TypedArrayObject.h"#include"jsobjinlines.h"#include"gc/Heap-inl.h"namespacejs{inlineuint8_t*NativeObject::fixedData(size_tnslots)const{MOZ_ASSERT(ClassCanHaveFixedData(getClass()));MOZ_ASSERT(nslots==numFixedSlots()+(hasPrivate()?1:0));returnreinterpret_cast<uint8_t*>(&fixedSlots()[nslots]);}inlinevoidNativeObject::removeLastProperty(JSContext*cx){MOZ_ASSERT(canRemoveLastProperty());JS_ALWAYS_TRUE(setLastProperty(cx,lastProperty()->previous()));}inlineboolNativeObject::canRemoveLastProperty(){/* * Check that the information about the object stored in the last * property's base shape is consistent with that stored in the previous * shape. If not consistent, then the last property cannot be removed as it * will induce a change in the object itself, and the object must be * converted to dictionary mode instead. See BaseShape comment in jsscope.h */MOZ_ASSERT(!inDictionaryMode());Shape*previous=lastProperty()->previous().get();returnprevious->getObjectFlags()==lastProperty()->getObjectFlags();}inlinevoidNativeObject::setShouldConvertDoubleElements(){MOZ_ASSERT(is<ArrayObject>()&&!hasEmptyElements());getElementsHeader()->setShouldConvertDoubleElements();}inlinevoidNativeObject::clearShouldConvertDoubleElements(){MOZ_ASSERT(is<ArrayObject>()&&!hasEmptyElements());getElementsHeader()->clearShouldConvertDoubleElements();}inlinevoidNativeObject::setDenseElementWithType(JSContext*cx,uint32_tindex,constValue&val){// Avoid a slow AddTypePropertyId call if the type is the same as the type// of the previous element.TypeSet::TypethisType=TypeSet::GetValueType(val);if(index==0||TypeSet::GetValueType(elements_[index-1])!=thisType)AddTypePropertyId(cx,this,JSID_VOID,thisType);setDenseElementMaybeConvertDouble(index,val);}inlinevoidNativeObject::initDenseElementWithType(JSContext*cx,uint32_tindex,constValue&val){MOZ_ASSERT(!shouldConvertDoubleElements());if(val.isMagic(JS_ELEMENTS_HOLE))markDenseElementsNotPacked(cx);elseAddTypePropertyId(cx,this,JSID_VOID,val);initDenseElement(index,val);}inlinevoidNativeObject::setDenseElementHole(JSContext*cx,uint32_tindex){MarkObjectGroupFlags(cx,this,OBJECT_FLAG_NON_PACKED);setDenseElement(index,MagicValue(JS_ELEMENTS_HOLE));}/* static */inlinevoidNativeObject::removeDenseElementForSparseIndex(JSContext*cx,HandleNativeObjectobj,uint32_tindex){MarkObjectGroupFlags(cx,obj,OBJECT_FLAG_NON_PACKED|OBJECT_FLAG_SPARSE_INDEXES);if(obj->containsDenseElement(index))obj->setDenseElementUnchecked(index,MagicValue(JS_ELEMENTS_HOLE));}inlineboolNativeObject::writeToIndexWouldMarkNotPacked(uint32_tindex){returngetElementsHeader()->initializedLength<index;}inlinevoidNativeObject::markDenseElementsNotPacked(JSContext*cx){MOZ_ASSERT(isNative());MarkObjectGroupFlags(cx,this,OBJECT_FLAG_NON_PACKED);}inlinevoidNativeObject::elementsRangeWriteBarrierPost(uint32_tstart,uint32_tcount){for(size_ti=0;i<count;i++){constValue&v=elements_[start+i];if(v.isObject()&&IsInsideNursery(&v.toObject())){zone()->group()->storeBuffer().putSlot(this,HeapSlot::Element,unshiftedIndex(start+i),count-i);return;}}}inlinevoidNativeObject::copyDenseElements(uint32_tdstStart,constValue*src,uint32_tcount){MOZ_ASSERT(dstStart+count<=getDenseCapacity());MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());#ifdef DEBUGfor(uint32_ti=0;i<count;++i)checkStoredValue(src[i]);#endifif(JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()){uint32_tnumShifted=getElementsHeader()->numShiftedElements();for(uint32_ti=0;i<count;++i){elements_[dstStart+i].set(this,HeapSlot::Element,dstStart+i+numShifted,src[i]);}}else{memcpy(&elements_[dstStart],src,count*sizeof(HeapSlot));elementsRangeWriteBarrierPost(dstStart,count);}}inlinevoidNativeObject::initDenseElements(uint32_tdstStart,constValue*src,uint32_tcount){MOZ_ASSERT(dstStart+count<=getDenseCapacity());MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());#ifdef DEBUGfor(uint32_ti=0;i<count;++i)checkStoredValue(src[i]);#endifmemcpy(&elements_[dstStart],src,count*sizeof(HeapSlot));elementsRangeWriteBarrierPost(dstStart,count);}inlineboolNativeObject::tryShiftDenseElements(uint32_tcount){ObjectElements*header=getElementsHeader();if(header->initializedLength==count||count>ObjectElements::MaxShiftedElements||header->isCopyOnWrite()||header->isFrozen()||header->hasNonwritableArrayLength()){returnfalse;}shiftDenseElementsUnchecked(count);returntrue;}inlinevoidNativeObject::shiftDenseElementsUnchecked(uint32_tcount){ObjectElements*header=getElementsHeader();MOZ_ASSERT(count>0);MOZ_ASSERT(count<header->initializedLength);if(MOZ_UNLIKELY(header->numShiftedElements()+count>ObjectElements::MaxShiftedElements)){moveShiftedElements();header=getElementsHeader();}prepareElementRangeForOverwrite(0,count);header->addShiftedElements(count);elements_+=count;ObjectElements*newHeader=getElementsHeader();memmove(newHeader,header,sizeof(ObjectElements));}inlinevoidNativeObject::moveDenseElements(uint32_tdstStart,uint32_tsrcStart,uint32_tcount){MOZ_ASSERT(dstStart+count<=getDenseCapacity());MOZ_ASSERT(srcStart+count<=getDenseInitializedLength());MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());/* * Using memmove here would skip write barriers. Also, we need to consider * an array containing [A, B, C], in the following situation: * * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code. * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C]. * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C). * * Since normal marking never happens on B, it is very important that the * write barrier is invoked here on B, despite the fact that it exists in * the array before and after the move. */if(JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()){uint32_tnumShifted=getElementsHeader()->numShiftedElements();if(dstStart<srcStart){HeapSlot*dst=elements_+dstStart;HeapSlot*src=elements_+srcStart;for(uint32_ti=0;i<count;i++,dst++,src++)dst->set(this,HeapSlot::Element,dst-elements_+numShifted,*src);}else{HeapSlot*dst=elements_+dstStart+count-1;HeapSlot*src=elements_+srcStart+count-1;for(uint32_ti=0;i<count;i++,dst--,src--)dst->set(this,HeapSlot::Element,dst-elements_+numShifted,*src);}}else{memmove(elements_+dstStart,elements_+srcStart,count*sizeof(HeapSlot));elementsRangeWriteBarrierPost(dstStart,count);}}inlinevoidNativeObject::moveDenseElementsNoPreBarrier(uint32_tdstStart,uint32_tsrcStart,uint32_tcount){MOZ_ASSERT(!shadowZone()->needsIncrementalBarrier());MOZ_ASSERT(dstStart+count<=getDenseCapacity());MOZ_ASSERT(srcStart+count<=getDenseCapacity());MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());memmove(elements_+dstStart,elements_+srcStart,count*sizeof(Value));elementsRangeWriteBarrierPost(dstStart,count);}inlinevoidNativeObject::ensureDenseInitializedLengthNoPackedCheck(JSContext*cx,uint32_tindex,uint32_textra){MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());/* * Ensure that the array's contents have been initialized up to index, and * mark the elements through 'index + extra' as initialized in preparation * for a write. */MOZ_ASSERT(index+extra<=getDenseCapacity());uint32_t&initlen=getElementsHeader()->initializedLength;if(initlen<index+extra){uint32_tnumShifted=getElementsHeader()->numShiftedElements();size_toffset=initlen;for(HeapSlot*sp=elements_+initlen;sp!=elements_+(index+extra);sp++,offset++){sp->init(this,HeapSlot::Element,offset+numShifted,MagicValue(JS_ELEMENTS_HOLE));}initlen=index+extra;}}inlinevoidNativeObject::ensureDenseInitializedLength(JSContext*cx,uint32_tindex,uint32_textra){if(writeToIndexWouldMarkNotPacked(index))markDenseElementsNotPacked(cx);ensureDenseInitializedLengthNoPackedCheck(cx,index,extra);}DenseElementResultNativeObject::extendDenseElements(JSContext*cx,uint32_trequiredCapacity,uint32_textra){MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());/* * Don't grow elements for non-extensible objects or watched objects. Dense * elements can be added/written with no extensible or watchpoint checks as * long as there is capacity for them. */if(!nonProxyIsExtensible()||watched()){MOZ_ASSERT(getDenseCapacity()==0);returnDenseElementResult::Incomplete;}/* * Don't grow elements for objects which already have sparse indexes. * This avoids needing to count non-hole elements in willBeSparseElements * every time a new index is added. */if(isIndexed())returnDenseElementResult::Incomplete;/* * We use the extra argument also as a hint about number of non-hole * elements to be inserted. */if(requiredCapacity>MIN_SPARSE_INDEX&&willBeSparseElements(requiredCapacity,extra)){returnDenseElementResult::Incomplete;}if(!growElements(cx,requiredCapacity))returnDenseElementResult::Failure;returnDenseElementResult::Success;}inlineDenseElementResultNativeObject::ensureDenseElements(JSContext*cx,uint32_tindex,uint32_textra){MOZ_ASSERT(isNative());if(writeToIndexWouldMarkNotPacked(index))markDenseElementsNotPacked(cx);if(!maybeCopyElementsForWrite(cx))returnDenseElementResult::Failure;uint32_tcurrentCapacity=getDenseCapacity();uint32_trequiredCapacity;if(extra==1){/* Optimize for the common case. */if(index<currentCapacity){ensureDenseInitializedLengthNoPackedCheck(cx,index,1);returnDenseElementResult::Success;}requiredCapacity=index+1;if(requiredCapacity==0){/* Overflow. */returnDenseElementResult::Incomplete;}}else{requiredCapacity=index+extra;if(requiredCapacity<index){/* Overflow. */returnDenseElementResult::Incomplete;}if(requiredCapacity<=currentCapacity){ensureDenseInitializedLengthNoPackedCheck(cx,index,extra);returnDenseElementResult::Success;}}DenseElementResultresult=extendDenseElements(cx,requiredCapacity,extra);if(result!=DenseElementResult::Success)returnresult;ensureDenseInitializedLengthNoPackedCheck(cx,index,extra);returnDenseElementResult::Success;}inlineValueNativeObject::getDenseOrTypedArrayElement(uint32_tidx){if(is<TypedArrayObject>())returnas<TypedArrayObject>().getElement(idx);returngetDenseElement(idx);}/* static */inlineNativeObject*NativeObject::copy(JSContext*cx,gc::AllocKindkind,gc::InitialHeapheap,HandleNativeObjecttemplateObject){RootedShapeshape(cx,templateObject->lastProperty());RootedObjectGroupgroup(cx,templateObject->group());MOZ_ASSERT(!templateObject->denseElementsAreCopyOnWrite());JSObject*baseObj;JS_TRY_VAR_OR_RETURN_NULL(cx,baseObj,create(cx,kind,heap,shape,group));NativeObject*obj=&baseObj->as<NativeObject>();size_tspan=shape->slotSpan();if(span){uint32_tnumFixed=templateObject->numFixedSlots();constValue*fixed=&templateObject->getSlot(0);// Only copy elements which are registered in the shape, even if the// number of fixed slots is larger.if(span<numFixed)numFixed=span;obj->copySlotRange(0,fixed,numFixed);if(numFixed<span){uint32_tnumSlots=span-numFixed;constValue*slots=&templateObject->getSlot(numFixed);obj->copySlotRange(numFixed,slots,numSlots);}}returnobj;}MOZ_ALWAYS_INLINEvoidNativeObject::setSlotWithType(JSContext*cx,Shape*shape,constValue&value,booloverwriting){setSlot(shape->slot(),value);if(overwriting)shape->setOverwritten();AddTypePropertyId(cx,this,shape->propid(),value);}inlinevoidNativeObject::updateShapeAfterMovingGC(){Shape*shape=shape_;if(IsForwarded(shape))shape_.unsafeSet(Forwarded(shape));}inlineboolNativeObject::isInWholeCellBuffer()const{constgc::TenuredCell*cell=&asTenured();gc::ArenaCellSet*cells=cell->arena()->bufferedCells();returncells&&cells->hasCell(cell);}/* static */inlineJS::Result<NativeObject*,JS::OOM&>NativeObject::create(JSContext*cx,js::gc::AllocKindkind,js::gc::InitialHeapheap,js::HandleShapeshape,js::HandleObjectGroupgroup){debugCheckNewObject(group,shape,kind,heap);constjs::Class*clasp=group->clasp();MOZ_ASSERT(clasp->isNative());size_tnDynamicSlots=dynamicSlotsCount(shape->numFixedSlots(),shape->slotSpan(),clasp);JSObject*obj=js::Allocate<JSObject>(cx,kind,nDynamicSlots,heap,clasp);if(!obj)returncx->alreadyReportedOOM();NativeObject*nobj=static_cast<NativeObject*>(obj);nobj->group_.init(group);nobj->initShape(shape);// Note: slots are created and assigned internally by Allocate<JSObject>.nobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);if(clasp->hasPrivate())nobj->privateRef(shape->numFixedSlots())=nullptr;if(size_tspan=shape->slotSpan())nobj->initializeSlotRange(0,span);// JSFunction's fixed slots expect POD-style initialization.if(clasp->isJSFunction()){MOZ_ASSERT(kind==js::gc::AllocKind::FUNCTION||kind==js::gc::AllocKind::FUNCTION_EXTENDED);size_tsize=kind==js::gc::AllocKind::FUNCTION?sizeof(JSFunction):sizeof(js::FunctionExtended);memset(nobj->as<JSFunction>().fixedSlots(),0,size-sizeof(js::NativeObject));if(kind==js::gc::AllocKind::FUNCTION_EXTENDED){// SetNewObjectMetadata may gc, which will be unhappy if flags &// EXTENDED doesn't match the arena's AllocKind.nobj->as<JSFunction>().setFlags(JSFunction::EXTENDED);}}if(clasp->shouldDelayMetadataBuilder())cx->compartment()->setObjectPendingMetadata(cx,nobj);elsenobj=SetNewObjectMetadata(cx,nobj);js::gc::TraceCreateObject(nobj);returnnobj;}MOZ_ALWAYS_INLINEuint32_tNativeObject::numDynamicSlots()const{returndynamicSlotsCount(numFixedSlots(),slotSpan(),getClass());}/* static */MOZ_ALWAYS_INLINEuint32_tNativeObject::dynamicSlotsCount(uint32_tnfixed,uint32_tspan,constClass*clasp){if(span<=nfixed)return0;span-=nfixed;// Increase the slots to SLOT_CAPACITY_MIN to decrease the likelihood// the dynamic slots need to get increased again. ArrayObjects ignore// this because slots are uncommon in that case.if(clasp!=&ArrayObject::class_&&span<=SLOT_CAPACITY_MIN)returnSLOT_CAPACITY_MIN;uint32_tslots=mozilla::RoundUpPow2(span);MOZ_ASSERT(slots>=span);returnslots;}/* static */MOZ_ALWAYS_INLINEuint32_tNativeObject::dynamicSlotsCount(Shape*shape){returndynamicSlotsCount(shape->numFixedSlots(),shape->slotSpan(),shape->getObjectClass());}MOZ_ALWAYS_INLINEboolNativeObject::updateSlotsForSpan(JSContext*cx,size_toldSpan,size_tnewSpan){MOZ_ASSERT(oldSpan!=newSpan);size_toldCount=dynamicSlotsCount(numFixedSlots(),oldSpan,getClass());size_tnewCount=dynamicSlotsCount(numFixedSlots(),newSpan,getClass());if(oldSpan<newSpan){if(oldCount<newCount&&!growSlots(cx,oldCount,newCount))returnfalse;if(newSpan==oldSpan+1)initSlotUnchecked(oldSpan,UndefinedValue());elseinitializeSlotRange(oldSpan,newSpan-oldSpan);}else{/* Trigger write barriers on the old slots before reallocating. */prepareSlotRangeForOverwrite(newSpan,oldSpan);invalidateSlotRange(newSpan,oldSpan-newSpan);if(oldCount>newCount)shrinkSlots(cx,oldCount,newCount);}returntrue;}MOZ_ALWAYS_INLINEboolNativeObject::setLastProperty(JSContext*cx,Shape*shape){MOZ_ASSERT(!inDictionaryMode());MOZ_ASSERT(!shape->inDictionary());MOZ_ASSERT(shape->zone()==zone());MOZ_ASSERT(shape->numFixedSlots()==numFixedSlots());MOZ_ASSERT(shape->getObjectClass()==getClass());size_toldSpan=lastProperty()->slotSpan();size_tnewSpan=shape->slotSpan();if(oldSpan==newSpan){shape_=shape;returntrue;}if(MOZ_UNLIKELY(!updateSlotsForSpan(cx,oldSpan,newSpan)))returnfalse;shape_=shape;returntrue;}/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */staticinlinePlainObject*CopyInitializerObject(JSContext*cx,HandlePlainObjectbaseobj,NewObjectKindnewKind=GenericObject){MOZ_ASSERT(!baseobj->inDictionaryMode());gc::AllocKindallocKind=gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());allocKind=gc::GetBackgroundAllocKind(allocKind);MOZ_ASSERT_IF(baseobj->isTenured(),allocKind==baseobj->asTenured().getAllocKind());RootedPlainObjectobj(cx,NewBuiltinClassInstance<PlainObject>(cx,allocKind,newKind));if(!obj)returnnullptr;if(!obj->setLastProperty(cx,baseobj->lastProperty()))returnnullptr;returnobj;}inlineNativeObject*NewNativeObjectWithGivenTaggedProto(JSContext*cx,constClass*clasp,Handle<TaggedProto>proto,gc::AllocKindallocKind,NewObjectKindnewKind){returnMaybeNativeObject(NewObjectWithGivenTaggedProto(cx,clasp,proto,allocKind,newKind));}inlineNativeObject*NewNativeObjectWithGivenTaggedProto(JSContext*cx,constClass*clasp,Handle<TaggedProto>proto,NewObjectKindnewKind=GenericObject){returnMaybeNativeObject(NewObjectWithGivenTaggedProto(cx,clasp,proto,newKind));}inlineNativeObject*NewNativeObjectWithGivenProto(JSContext*cx,constClass*clasp,HandleObjectproto,gc::AllocKindallocKind,NewObjectKindnewKind){returnMaybeNativeObject(NewObjectWithGivenProto(cx,clasp,proto,allocKind,newKind));}inlineNativeObject*NewNativeObjectWithGivenProto(JSContext*cx,constClass*clasp,HandleObjectproto,NewObjectKindnewKind=GenericObject){returnMaybeNativeObject(NewObjectWithGivenProto(cx,clasp,proto,newKind));}inlineNativeObject*NewNativeObjectWithClassProto(JSContext*cx,constClass*clasp,HandleObjectproto,gc::AllocKindallocKind,NewObjectKindnewKind=GenericObject){returnMaybeNativeObject(NewObjectWithClassProto(cx,clasp,proto,allocKind,newKind));}inlineNativeObject*NewNativeObjectWithClassProto(JSContext*cx,constClass*clasp,HandleObjectproto,NewObjectKindnewKind=GenericObject){returnMaybeNativeObject(NewObjectWithClassProto(cx,clasp,proto,newKind));}/* * Call obj's resolve hook. * * cx and id are the parameters initially passed to the ongoing lookup; * propp and recursedp are its out parameters. * * There are four possible outcomes: * * - On failure, report an error or exception and return false. * * - If we are already resolving a property of obj, set *recursedp = true, * and return true. * * - If the resolve hook finds or defines the sought property, set propp * appropriately, set *recursedp = false, and return true. * * - Otherwise no property was resolved. Set propp to nullptr and * *recursedp = false and return true. */staticMOZ_ALWAYS_INLINEboolCallResolveOp(JSContext*cx,HandleNativeObjectobj,HandleIdid,MutableHandle<PropertyResult>propp,bool*recursedp){// Avoid recursion on (obj, id) already being resolved on cx.AutoResolvingresolving(cx,obj,id);if(resolving.alreadyStarted()){// Already resolving id in obj, suppress recursion.*recursedp=true;returntrue;}*recursedp=false;boolresolved=false;if(!obj->getClass()->getResolve()(cx,obj,id,&resolved))returnfalse;if(!resolved)returntrue;// Assert the mayResolve hook, if there is one, returns true for this// property.MOZ_ASSERT_IF(obj->getClass()->getMayResolve(),obj->getClass()->getMayResolve()(cx->names(),id,obj));if(JSID_IS_INT(id)&&obj->containsDenseElement(JSID_TO_INT(id))){propp.setDenseOrTypedArrayElement();returntrue;}MOZ_ASSERT(!obj->is<TypedArrayObject>());RootedShapeshape(cx,obj->lookup(cx,id));if(shape)propp.setNativeProperty(shape);elsepropp.setNotFound();returntrue;}template<AllowGCallowGC>staticMOZ_ALWAYS_INLINEboolLookupOwnPropertyInline(JSContext*cx,typenameMaybeRooted<NativeObject*,allowGC>::HandleTypeobj,typenameMaybeRooted<jsid,allowGC>::HandleTypeid,typenameMaybeRooted<PropertyResult,allowGC>::MutableHandleTypepropp,bool*donep){// Check for a native dense element.if(JSID_IS_INT(id)&&obj->containsDenseElement(JSID_TO_INT(id))){propp.setDenseOrTypedArrayElement();*donep=true;returntrue;}// Check for a typed array element. Integer lookups always finish here// so that integer properties on the prototype are ignored even for out// of bounds accesses.if(obj->templateis<TypedArrayObject>()){uint64_tindex;if(IsTypedArrayIndex(id,&index)){if(index<obj->templateas<TypedArrayObject>().length())propp.setDenseOrTypedArrayElement();elsepropp.setNotFound();*donep=true;returntrue;}}// Check for a native property. Call Shape::search directly (instead of// NativeObject::lookup) because it's inlined.if(Shape*shape=obj->lastProperty()->search(cx,id)){propp.setNativeProperty(shape);*donep=true;returntrue;}// id was not found in obj. Try obj's resolve hook, if any.if(obj->getClass()->getResolve()){MOZ_ASSERT(!cx->helperThread());if(!allowGC)returnfalse;boolrecursed;if(!CallResolveOp(cx,MaybeRooted<NativeObject*,allowGC>::toHandle(obj),MaybeRooted<jsid,allowGC>::toHandle(id),MaybeRooted<PropertyResult,allowGC>::toMutableHandle(propp),&recursed)){returnfalse;}if(recursed){propp.setNotFound();*donep=true;returntrue;}if(propp){*donep=true;returntrue;}}propp.setNotFound();*donep=false;returntrue;}/* * Simplified version of LookupOwnPropertyInline that doesn't call resolve * hooks. */staticinlinevoidNativeLookupOwnPropertyNoResolve(JSContext*cx,HandleNativeObjectobj,HandleIdid,MutableHandle<PropertyResult>result){// Check for a native dense element.if(JSID_IS_INT(id)&&obj->containsDenseElement(JSID_TO_INT(id))){result.setDenseOrTypedArrayElement();return;}// Check for a typed array element.if(obj->is<TypedArrayObject>()){uint64_tindex;if(IsTypedArrayIndex(id,&index)){if(index<obj->as<TypedArrayObject>().length())result.setDenseOrTypedArrayElement();elseresult.setNotFound();return;}}// Check for a native property.if(Shape*shape=obj->lookup(cx,id))result.setNativeProperty(shape);elseresult.setNotFound();}template<AllowGCallowGC>staticMOZ_ALWAYS_INLINEboolLookupPropertyInline(JSContext*cx,typenameMaybeRooted<NativeObject*,allowGC>::HandleTypeobj,typenameMaybeRooted<jsid,allowGC>::HandleTypeid,typenameMaybeRooted<JSObject*,allowGC>::MutableHandleTypeobjp,typenameMaybeRooted<PropertyResult,allowGC>::MutableHandleTypepropp){/* Search scopes starting with obj and following the prototype link. */typenameMaybeRooted<NativeObject*,allowGC>::RootTypecurrent(cx,obj);while(true){booldone;if(!LookupOwnPropertyInline<allowGC>(cx,current,id,propp,&done))returnfalse;if(done){if(propp)objp.set(current);elseobjp.set(nullptr);returntrue;}typenameMaybeRooted<JSObject*,allowGC>::RootTypeproto(cx,current->staticPrototype());if(!proto)break;if(!proto->isNative()){MOZ_ASSERT(!cx->helperThread());if(!allowGC)returnfalse;returnLookupProperty(cx,MaybeRooted<JSObject*,allowGC>::toHandle(proto),MaybeRooted<jsid,allowGC>::toHandle(id),MaybeRooted<JSObject*,allowGC>::toMutableHandle(objp),MaybeRooted<PropertyResult,allowGC>::toMutableHandle(propp));}current=&proto->templateas<NativeObject>();}objp.set(nullptr);propp.setNotFound();returntrue;}inlineboolThrowIfNotConstructing(JSContext*cx,constCallArgs&args,constchar*builtinName){if(args.isConstructing())returntrue;returnJS_ReportErrorFlagsAndNumberASCII(cx,JSREPORT_ERROR,GetErrorMessage,nullptr,JSMSG_BUILTIN_CTOR_NO_NEW,builtinName);}inlineboolIsPackedArray(JSObject*obj){returnobj->is<ArrayObject>()&&!obj->hasLazyGroup()&&!obj->group()->hasAllFlags(OBJECT_FLAG_NON_PACKED)&&obj->as<ArrayObject>().getDenseInitializedLength()==obj->as<ArrayObject>().length();}}// namespace js#endif /* vm_NativeObject_inl_h */